package com.hosever.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;

/**
 * 文件工具类
 * 
 * @author hosever
 * 
 */
public class FileUtils {

	/**
	 * 文件复制
	 * 
	 * @param oldPath
	 *            旧路径
	 * @param newPath
	 *            新路径
	 * @param fileName
	 *            文件名
	 * @throws IOException
	 */
	public static void copyFile(String oldPath, String newPath, String fileName)
			throws IOException {
		InputStream inStream = null;
		FileOutputStream fs = null;
		try {
			int bytesum = 0;
			int byteread = 0;
			byte[] buffer = file2ByteArray_BigFile(oldPath + fileName);
			inStream = new FileInputStream(oldPath + fileName);
			FileUtils.dirMaker(newPath);
			File file = new File(newPath, fileName);
			if (!file.exists()) {
				file.createNewFile();
			}
			fs = new FileOutputStream(file);
			while ((byteread = inStream.read(buffer)) != -1) {
				bytesum += byteread; // 字节数 文件大小
				fs.write(buffer, 0, byteread);
			}
			System.out.println("======复制文件[" + fileName + "]=======");
			System.out.println("从" + oldPath + fileName);
			System.out.println("到" + newPath + fileName);

			if (bytesum < 1024) {
				System.out.println("共" + bytesum + "B");
			} else if (bytesum > 1024 && bytesum < 1024 * 1024) {
				double kb = (double) bytesum / 1024;
				System.out.println("共" + kb + "KB");
			} else {
				double mb = (double) bytesum / 1024 / 1024;
				System.out.println("共" + mb + "MB");
			}
			System.out.println();
		} finally {
			if (inStream != null) {
				inStream.close();
			}
			if (fs != null) {
				fs.flush();
				fs.close();
			}
		}
	}

	/**
	 * 文件夹生成器
	 * 
	 * @param root
	 *            根路径
	 * @param dir
	 *            文件夹
	 */
	public static void dirMaker(String root, String dir) {
		String path = root + dir;
		dirMaker(path);
	}

	/**
	 * 文件夹生成器
	 * 
	 * @param path
	 *            路径
	 */
	public static void dirMaker(String path) {
		File file = new File(path);
		file.mkdirs();
		System.out.println("===创建路径===");
		System.out.println(path);
	}

	/**
	 * 文件转byte数组（nio同步非阻塞 方式）
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static byte[] file2ByteArray_nio(File file) throws IOException {
		if (!file.exists()) {
			throw new FileNotFoundException(file.getName());
		}

		FileChannel channel = null;
		FileInputStream fs = null;
		try {
			fs = new FileInputStream(file);//文件包装成文件输流
			channel = fs.getChannel();//获取文件通道
			ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());//分配一个新的字节缓存区，大小为该通道的大小
			while ((channel.read(byteBuffer)) > 0) {
				// 将字节序列从此通道读入给定的缓冲区byteBuffer
				// System.out.println("reading");
			}
			return byteBuffer.array();
		} finally {
			try {
				channel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				fs.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 文件转byte数组(大文件，高性能)
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("resource")
	public static byte[] file2ByteArray_BigFile(String filename)
			throws IOException {

		FileChannel fc = null;
		try {
			//创建从中读取的随机访问文件流，该文件具有指定名称。
			//"r"	以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
			//"rw"	打开以便读取和写入。如果该文件尚不存在，则尝试创建该文件。
			//"rws"	打开以便读取和写入，对于 "rw"，还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
			//"rwd" 打开以便读取和写入，对于 "rw"，还要求对文件内容的每个更新都同步写入到底层存储设备。
			fc = new RandomAccessFile(filename, "r").getChannel();
			//直接字节缓冲区，其内容是文件的内存映射区域。
			//fc.map将此通道的文件区域直接映射到内存中。
			MappedByteBuffer byteBuffer = fc.map(MapMode.READ_ONLY, 0,
					fc.size()).load();
			// System.out.println(byteBuffer.isLoaded());
			byte[] result = new byte[(int) fc.size()];
			if (byteBuffer.remaining() > 0) {
				// System.out.println("remain");
				
				//此方法将此缓冲区的字节传输到给定的目标数组中。
				//byteBuffer.remaining()返回当前位置与限制之间的元素数。
				byteBuffer.get(result, 0, byteBuffer.remaining());
			}
			return result;
		} finally {
			if (fc != null) {
				fc.close();
			}
		}
	}
	
	/**
	 * 补齐文件夹分隔符
	 * 
	 * @param dirName
	 * @return
	 */
	public static String addSeparatorIfNec(String dirName) {
		if (SeverStringUtils.isBlank(dirName)) {
			String dirSeparator = File.separator;
			if (!dirName.endsWith(dirSeparator))
				dirName += dirSeparator;
		}
		return dirName;
	}
}
